package com.mtw.bbs.common.web.interceptor;


import com.mtw.bbs.common.core.enums.ResultCode;
import com.mtw.bbs.common.core.exception.BusinessException;
import com.mtw.bbs.common.web.annotation.AccessLimit;
import com.mtw.bbs.common.core.security.AccessLimitService;
import com.mtw.bbs.common.web.util.AccessLimitAESUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import java.util.Objects;

/**
 * 接口防刷拦截处理
 */
@Slf4j
public class AccessLimitInterceptor implements HandlerInterceptor {

    private final String applicationName;
    private final AccessLimitService accessLimitService;



    public AccessLimitInterceptor(AccessLimitService accessLimitService,String applicationName){
        this.accessLimitService = accessLimitService;
        this.applicationName = applicationName;
    }


    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler){

        // 无需限流
        if (request.getRequestURI().contains("provide/")){
            return true;
        }

        if (handler instanceof HandlerMethod) {
            // 访问的是接口方法，转化为待访问的目标方法对象
            HandlerMethod targetMethod = (HandlerMethod) handler;

            // 获取目标接口方法所在类的注解@AccessLimit
            AccessLimit targetClassAnnotation = targetMethod.getMethod().getDeclaringClass().getAnnotation(AccessLimit.class);

            // 定义标记位，标记此类是否加了@AccessLimit注解
            boolean isBrushForAllInterface = false;

            String xId = request.getHeader("X-Request-Id");
            String uri = request.getRequestURI();
            String decryptXid = AccessLimitAESUtil.decrypt(xId);
            long second = 0L;
            long maxTime = 0L;
            if (!Objects.isNull(targetClassAnnotation)) {
                log.info("目标接口方法所在类上有@AccessLimit注解");
                isBrushForAllInterface = true;
                second = targetClassAnnotation.second();
                maxTime = targetClassAnnotation.maxTime();
            }

            // 取出目标方法中的 AccessLimit 注解
            AccessLimit accessLimit = targetMethod.getMethodAnnotation(AccessLimit.class);

            // 判断此方法接口是否要进行防刷处理
            if (!Objects.isNull(accessLimit)) {
                // 需要进行防刷处理，接下来是处理逻辑
                second = accessLimit.second();
                maxTime = accessLimit.maxTime();
                if (!accessLimitService.isAcquire(second, maxTime, applicationName, decryptXid, uri)) {
                    throw new BusinessException(ResultCode.SYSTEM_BUSY.getCode(),ResultCode.SYSTEM_BUSY.getMsg());
                }
            } else {
                // 目标接口方法处无@AccessLimit注解，但还要看看其类上是否加了(类上有加，代表针对此类下所有接口方法都要进行防刷处理)
                if (isBrushForAllInterface && !accessLimitService.isAcquire(second, maxTime, applicationName, decryptXid, uri)) {
                    throw new BusinessException(ResultCode.SYSTEM_BUSY.getCode(),ResultCode.SYSTEM_BUSY.getMsg());
                }
            }
        }
        return true;
    }




}


